package com.cqie.hospitalescort.exception;

import com.cqie.hospitalescort.model.Result;
import com.cqie.hospitalescort.model.constants.ResultCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.io.IOException;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 全局异常处理
 */
@ControllerAdvice
@Slf4j
@Component
public class GlobalExceptionHandler {

    @ExceptionHandler(BadCredentialsException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    @ResponseBody
    public Result<?> handleRuntimeException(BadCredentialsException ex) {
        return new Result<>(ResultCode.UNAUTHORIZED, ex.getMessage());
    }

    /**
     * 用于登录时用户名未找到而抛出的异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(UsernameNotFoundException.class)
    @ResponseBody
    public Result<?> handleUsernameNotFoundException(UsernameNotFoundException e) {
        return new Result<>(ResultCode.GLOBALEXCEPTION, "用户名未找到！" + e.getMessage());
    }

    /**
     * 权限异常设置返回信息
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(AccessDeniedException.class)
    @ResponseStatus(HttpStatus.FORBIDDEN)
    @ResponseBody
    public Result<?> handleAccessDeniedException(AccessDeniedException ex) {
        log.error("路径：{}权限不足,原因：{}", ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest().getRequestURI(), ex.getMessage());
        return new Result<>(ResultCode.FORBIDDEN, "权限不足！");
    }

    @ExceptionHandler(BindException.class)
    @ResponseBody
    public Result<?> handleValidationExceptions(BindException ex) {
        // 提取所有字段级别的错误信息，并过滤出中文部分
        String errorMessage = ex.getBindingResult().getAllErrors().stream()
                .map(DefaultMessageSourceResolvable::getDefaultMessage)
                .filter(message -> message != null && isChinese(message))
                .collect(Collectors.joining(";"));

        return new Result<>(ResultCode.ERROR, errorMessage);
    }

    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    public Result<Map<String, String>> handleConstraintViolationException(ConstraintViolationException ex) {
        return new Result<>(ResultCode.ERROR, ex.getConstraintViolations().stream().map(ConstraintViolation::getMessage).filter(message -> message != null && isChinese(message))
                .collect(Collectors.joining(";")));
    }

    @ExceptionHandler(RuntimeException.class)
    @ResponseBody
    public Result<?> handleRuntimeException (RuntimeException ex) {
        return new Result<>(ResultCode.ERROR, ex.getMessage());
    }

    @ExceptionHandler(AuthenticationException.class)
    @ResponseBody
    public Result<?> handleAuthenticationException(AuthenticationException ex, HttpServletResponse response) throws IOException {
        return new Result<>(HttpServletResponse.SC_UNAUTHORIZED, "登录过期！");
    }


    private boolean isChinese(String str) {
        for (int i = 0; i < str.length(); i++) {
            char ch = str.charAt(i);
            if (Character.UnicodeBlock.of(ch) == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS) {
                return true;
            }
        }
        return false;
    }
}